package com.xbongbong.pay.platform.wechatpay.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.pay.enums.PayErrorEnum;
import com.xbongbong.pay.exception.PayApiException;
import com.xbongbong.pay.platform.wechatpay.client.WeChatClient;
import com.xbongbong.pay.platform.wechatpay.config.WeChatPayConfig;
import com.xbongbong.pay.platform.wechatpay.config.WeChatPayMeta;
import com.xbongbong.pay.platform.wechatpay.config.WeChatPayMetaContainer;
import com.xbongbong.pay.platform.wechatpay.enums.WeChatServerEnum;
import com.xbongbong.pay.platform.wechatpay.enums.WeChatV3UrlEnum;
import com.xbongbong.pay.platform.wechatpay.pojo.request.partner.WeChatPayPartnerCloseOrderRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.partner.WeChatPayPartnerH5TransactionsRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.partner.WeChatPayPartnerNativeTransactionsRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.partner.WeChatPayPartnerQueryOrder4MchRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.partner.WeChatPayPartnerQueryOrder4WeChatRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.request.partner.WeChatPayPartnerTransactionsRequest;
import com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerH5TransactionsResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerNativeTransactionsResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerQueryOrderResponse;
import com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerTransactionsResponse;
import com.xbongbong.pay.pojo.PayHttpResponse;
import com.xbongbong.pay.utils.PayHttpUtil;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 服务商模式API
 * @author 魏荣杰
 * @date 2021/2/19 09:19
 * @since
 * @version
 */
@Service("weChatPayPartnerApi")
public class WeChatPayPartnerApi {
    private static final Logger LOG = LoggerFactory.getLogger(WeChatPayPartnerApi.class);

    @Resource
    private WeChatPayMetaContainer weChatPayMetaContainer;

    /**
     * Description: JSAPI/小程序下单API 服务商模式
     * @param request 请求体
     * @param mchId 商户 id
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerTransactionsResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/2/19 09:33
     * @since
     */
    public WeChatPayPartnerTransactionsResponse orderForJsapi(WeChatPayPartnerTransactionsRequest request, String mchId) throws PayApiException {
        try {

            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(wechatMeta.getKeyPair().getPrivate(), mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.PARTNER_TRANSACTIONS_JSAPI);
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                String prepayId = jsonObject.getString("prepay_id");
                Map<String, String> headerMap = payHttpResponse.getHeaders();
                String nonceStr = headerMap.get("Wechatpay-Nonce");
                String timeStamp = headerMap.get("Wechatpay-Timestamp");

                String packages = "prepay_id=" + prepayId;
                String buildSignMessage = WeChatSignUtil.buildSignMessage(v3.getAppId(), timeStamp, nonceStr, packages);
                String signature = WeChatSignUtil.createSign4V3(buildSignMessage, wechatMeta.getKeyPair().getPrivate());
                return new WeChatPayPartnerTransactionsResponse(timeStamp, nonceStr, "RSA", signature, v3.getAppId(), packages);
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: H5下单API(服务商模式)
     * @param request
     * @param mchId
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerH5TransactionsResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/2/20 15:38
     * @since
     */
    public WeChatPayPartnerH5TransactionsResponse orderForH5(WeChatPayPartnerH5TransactionsRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(wechatMeta.getKeyPair().getPrivate(), mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.PARTNER_TRANSACTIONS_H5);
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatPayPartnerH5TransactionsResponse.class);
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: Native下单API(服务商模式)
     * @param request
     * @param mchId
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerNativeTransactionsResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/2/22 09:37
     * @since
     */
    public WeChatPayPartnerNativeTransactionsResponse orderForNative(WeChatPayPartnerNativeTransactionsRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(wechatMeta.getKeyPair().getPrivate(), mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.PARTNER_TRANSACTIONS_NATIVE);
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatPayPartnerNativeTransactionsResponse.class);
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 微信支付订单号查询
     * @param request
     * @param mchId
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerQueryOrderResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/2/22 13:35
     * @since
     */
    public WeChatPayPartnerQueryOrderResponse queryOrderForWeChat(WeChatPayPartnerQueryOrder4WeChatRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(wechatMeta.getKeyPair().getPrivate(), mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.PARTNER_QUERY_ORDER_WECHAT, request.getTransactionId());
            PayHttpResponse payHttpResponse = PayHttpUtil.httpGetByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatPayPartnerQueryOrderResponse.class);
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 商户订单号查询
     * @param request
     * @param mchId
     * @return com.xbongbong.pay.platform.wechatpay.pojo.response.partner.WeChatPayPartnerQueryOrderResponse
     * @throws
     * @author 魏荣杰
     * @date 2021/2/22 13:35
     * @since
     */
    public WeChatPayPartnerQueryOrderResponse queryOrderForMch(WeChatPayPartnerQueryOrder4MchRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(wechatMeta.getKeyPair().getPrivate(), mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.PARTNER_QUERY_ORDER_MCH, request.getOutTradeNo());
            PayHttpResponse payHttpResponse = PayHttpUtil.httpGetByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200)) {
                return JSON.parseObject(jsonObject.toJSONString(), WeChatPayPartnerQueryOrderResponse.class);
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }

    /**
     * Description: 关单(服务商模式)
     * @param request
     * @param mchId
     * @return boolean
     * @throws
     * @author 魏荣杰
     * @date 2021/2/22 13:41
     * @since
     */
    public boolean closeOrder(WeChatPayPartnerCloseOrderRequest request, String mchId) throws PayApiException {
        try {
            WeChatPayMeta wechatMeta = weChatPayMetaContainer.getWechatMeta(mchId);
            WeChatPayConfig.V3 v3 = wechatMeta.getV3();
            CloseableHttpClient httpClient = WeChatClient.build(wechatMeta.getKeyPair().getPrivate(), mchId, wechatMeta.getSerialNumber(), v3.getAppV3Secret());

            String url = WeChatV3UrlEnum.getUrl(WeChatServerEnum.CHINA, WeChatV3UrlEnum.PARTNER_CLOSE_ORDER, request.getOutTradeNo());
            PayHttpResponse payHttpResponse = PayHttpUtil.httpPostByJson(httpClient, url, request, new HashMap<>());
            int status = payHttpResponse.getStatus();
            JSONObject jsonObject = payHttpResponse.getBody();
            if (Objects.equals(status, 200) || Objects.equals(status, 204)) {
                return true;
            } else {
                throw new PayApiException(status, jsonObject.getString("message"));
            }
        } catch (PayApiException e) {
            throw e;
        } catch (Exception e) {
            throw new PayApiException(PayErrorEnum.API_ERROR.getCode(), PayErrorEnum.API_ERROR.getMsg());
        }
    }
}
